package com.alin.flutter_ble_ota.tool.bluetooth

import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.content.Context
import com.alin.flutter_ble_ota.tool.ota.ble.BleManager
import com.alin.flutter_ble_ota.tool.ota.ble.interfaces.BleEventCallback
import com.alin.flutter_ble_ota.tool.ota.ble.model.BleScanInfo
import com.jieli.jl_bt_ota.util.BluetoothUtil
import com.jieli.jl_bt_ota.util.CHexConver
import com.jieli.jl_bt_ota.util.JL_Log
import com.alin.flutter_ble_ota.util.OtaConstant
import com.alin.flutter_ble_ota.tool.config.ConfigHelper
import com.alin.flutter_ble_ota.util.AppUtil
import java.util.*

/**
 * @author zqjasonZhong
 * @since 2022/9/14
 * @email zhongzhuocheng@zh-jieli.com
 * @desc 蓝牙操作辅助类
 */
class BluetoothHelper(context: Context) {

    private val configHelper = ConfigHelper.getInstance(context)
    private val bleManager = BleManager.getInstance(context)!!
    private val btEventCbHelper = BTEventCbHelper()

    companion object {

        const val TAG: String = "BluetoothHelper"

        @Volatile
        private var instance: BluetoothHelper? = null

        fun getInstance(c: Context): BluetoothHelper = instance ?: synchronized(this) {
            instance ?: BluetoothHelper(c).also { instance = it }
        }
    }

    private val bleEventCallback = object : BleEventCallback() {

        override fun onAdapterChange(bEnabled: Boolean) {
            btEventCbHelper.onAdapterChange(bEnabled)
        }

        override fun onDiscoveryBleChange(bStart: Boolean) {
            btEventCbHelper.onDiscoveryChange(bStart, OtaConstant.PROTOCOL_BLE)
        }

        override fun onDiscoveryBle(device: BluetoothDevice?, bleScanMessage: BleScanInfo?) {
            btEventCbHelper.onDiscovery(device, bleScanMessage)
        }

        override fun onBleConnection(device: BluetoothDevice?, status: Int) {
            btEventCbHelper.onDeviceConnection(device, OtaConstant.PROTOCOL_BLE, status)
        }

        override fun onBleDataNotification(
            device: BluetoothDevice?,
            serviceUuid: UUID?,
            characteristicsUuid: UUID?,
            data: ByteArray?
        ) {
            btEventCbHelper.onReceiveData(
                device,
                OtaConstant.PROTOCOL_BLE,
                characteristicsUuid,
                data
            )
        }

        override fun onBleDataBlockChanged(device: BluetoothDevice?, block: Int, status: Int) {
            btEventCbHelper.onBleMtuChange(device, block, status)
        }
    }


    init {
        bleManager.registerBleEventCallback(bleEventCallback)
    }

    fun destroy() {
        bleManager.unregisterBleEventCallback(bleEventCallback)
        bleManager.destroy()
        btEventCbHelper.release()
        instance = null
    }

    fun registerCallback(callback: OnBTEventCallback) {
        btEventCbHelper.registerCallback(callback)
    }

    fun unregisterCallback(callback: OnBTEventCallback) {
        btEventCbHelper.unregisterCallback(callback)
    }

    fun isConnected(): Boolean {
        return getConnectedDevice() != null
    }

    fun isDeviceConnected(device: BluetoothDevice?): Boolean {
        return BluetoothUtil.deviceEquals(getConnectedDevice(), device)
    }

    fun isScanning(): Boolean = bleManager.isBleScanning

    fun isConnecting(): Boolean = bleManager.isBleScanning

    fun getConnectedDevice(): BluetoothDevice? {
        return bleManager.connectedBtDevice
    }

    fun getConnectedGatt(): BluetoothGatt? {
        return if (configHelper.isBleWay()) {
            bleManager.getConnectedBtGatt(getConnectedDevice())
        } else {
            null
        }
    }

    fun getBleMtu(): Int {
        return if (configHelper.isBleWay()) {
            return bleManager.getBleMtu(getConnectedDevice())
        } else {
            20
        }
    }

    fun startScan(timeout: Long): Boolean {
        return bleManager.startLeScan(timeout)
    }

    fun stopScan() {
        bleManager.stopLeScan()
    }

    fun connectDevice(device: BluetoothDevice?): Boolean =
        bleManager.connectBleDevice(device)

    fun disconnectDevice(device: BluetoothDevice?) {
        bleManager.disconnectBleDevice(device)
    }

    fun connectBleDevice(device: BluetoothDevice?): Boolean =
        bleManager.connectBleDevice(device)

    fun reconnectDevice(address: String?, isUseNewAdv: Boolean) {
        if (configHelper.isBleWay()) {
            bleManager.reconnectDevice(address, isUseNewAdv)
        } else {
            //TODO:需要增加SPP自定义回连方式
        }
    }

    fun writeDataToDevice(bluetoothDevice: BluetoothDevice?, byteArray: ByteArray?): Boolean {
        if (null == bluetoothDevice || null == byteArray || byteArray.isEmpty()) return false
        if (bleManager.connectedBtDevice != null) {//目前连接的设备是ble
            bleManager.writeDataByBleAsync(
                bluetoothDevice,
                BleManager.BLE_UUID_SERVICE,
                BleManager.BLE_UUID_WRITE,
                byteArray
            ) { device, serviceUUID, characteristicUUID, result, data ->
                JL_Log.i(
                    TAG,
                    "-writeDataByBleAsync- device:${
                        printDeviceInfo(device)
                    }, result = $result,\ndata:[${
                        CHexConver.byte2HexStr(data)
                    }]"
                )
            }
        }
        return true
    }

    private fun printDeviceInfo(device: BluetoothDevice?): String? {
        return AppUtil.printBtDeviceInfo(device)
    }

}